;;;
;;; dec: pilot codes for decoding list-mode data
;;;      the working code will be included in suty
;;;      or vuty
;;; 
BITS 64
;;; 
;;;  LICENSE AGREEMENT:
;;; 
;;;  You agree that we don't agree to anything.
;;; 
;;; 
;;;  DISCLAIMER OF WARRANTIES:
;;; 
;;;  This software is provided to you "AS IS," and the authors and
;;;  contributors disclaim any warranty or liability obligations to you
;;;  of any kind, implied or express, including but not limited to the
;;;  warranties of merchantability, fitness for a particular purpose,
;;;  and non-infringement.
;;; 
;;; 
section .data align=16
lmdmaskall dq 0x0000ffff0000ffff,0
lmdmasklsb dq 0x0000003f0000003f,0
b0001 dd -1,0,0,0
;; ntamax  dd 20-1, 64-1, 20-1, 64-1
nt92amax  dd 20-1, (64-1)*92, 20-1, (64-1)*92
a2d2a1d1conv dd 24,0,24,0
nac2 dd 20,-96,20,-96
qnx dd 92,0,92,0
;;; 
section .text align=16
%assign rc   0x04 
%assign arg1 0x18
%assign arg2 0x20
%assign arg3 0x28
%assign arg4 0x30
%assign arg5 0x38
%assign arg6 0x40
;;; 
global decd_
global decs_
;; 	global decv_
global initdecv_
global initdecvq_
global decvq_
;;; 
;;; subroutine initdecv(a,b,c)
;;; integer*4,intent(in)::a,b,c
;;; 
initdecv_:
	push rbp
	mov rbp, rsp
	;;
	mov eax, edi
	mov [a2d2a1d1conv], eax
	mov [a2d2a1d1conv+4], eax
	mov [a2d2a1d1conv+8], eax
	mov [a2d2a1d1conv+12], eax
	;;
	mov eax, esi
	mov [nac2], eax
	mov [nac2+8], eax
	;;
	mov eax, edx
	neg eax
	mov [nac2+4], eax
	mov [nac2+12], eax
 	;;
	pop rbp
	ret
;;;
initdecvq_:
	
	push rbp
	mov rbp, rsp
	;;	
	mov [rbp-arg1], rdi 	; 1st na
	mov [rbp-arg2], rsi	; 2nd nt
	mov [rbp-arg3], rdx	; 3rd ndh
	mov [rbp-arg4], rcx	; 4th mgap
	;;
	mov eax, dword [rbp-arg1]	; rax = na

	mov dword [nac2], eax	; 20  call initdecv(na+mgap,na,C2)
	mov dword [nac2+8], eax	; 20

	dec eax
	mov [nt92amax], eax 	; 20-1
	mov [nt92amax+8], eax 	; 20-1
	inc eax

	mov ecx, dword [rbp-arg4]	; rcx = mgap
	add eax, ecx
	mov [a2d2a1d1conv], eax		; 24
	mov [a2d2a1d1conv+8], eax	; 24

	mov eax, dword [rbp-arg3]	; eax = ndh
	mov ecx, eax		; ecx = ndh
	dec ecx			; ecx = ndh-1
	push rcx		; <P1
	mul dword [rbp-arg1]	; eax = ndh*na
	push rax		; <P2
	pop rcx			; >P2 ecx = ndh*na
	pop rax			; >P1 eax = ndh-1
	mul dword [rbp-arg4]	; eax = (ndh-1)*mgap
	add eax, ecx		; eax = (ndh-1)*mgap+ndh*na = 92
	;;
	mov [qnx], eax
	mov [qnx+8], eax
	push rax		; P1 eax = 92
	;;
	add eax, dword [rbp-arg4]	; eax = 92+mgap = 96
	neg eax			; eax = -96
	mov [nac2+4], eax	;
	mov [nac2+12], eax
	;;
	pop rax			; >P1 eax = 92
	mov ecx, dword [rbp-arg2] ; ecx = 64
	dec ecx			  ; ecx = 64-1
	mul ecx			  ; eax = (64-1)*92
	mov [nt92amax+4], eax	  ;
	mov [nt92amax+12], eax
	;;
	pop rbp
	ret
;;;; 
;;; subroutine decd(event,pd,tad1,tad2)
;;; integer*8,intent(in)::event
;;; integer*4,intent(out)::pd
;;; integer*4,intent(out)::tad1(3),tad2(3)
;;;
decd_:
	push rbp
	mov rbp, rsp
	;;
	mov [rbp-arg1], rdi 	; 1st event
	mov [rbp-arg2], rsi	; 2nd Pr/Del
	mov [rbp-arg3], rdx	; 3rd tad1
	mov [rbp-arg4], rcx	; 4th tad2
	;;
	mov rax, rdi		; rax=ptr event
 	mov rax, [rax]

	;;
	xor rdx, rdx
	bt rax, 60		; CF=Pr/Del
	adc rdx, 0		; edx=Pr/Del
	mov rdi, [rbp-arg2]	; rdi=ptr pd
	mov dword [rdi], edx	; pd=Pr/Del
	;; 
	mov rdx, rax		; dl=T1
	and rdx, 0x3F		; lower 6 bits
	mov rdi, [rbp-arg3]	; rdi= ptr tad1
	mov dword [rdi], edx	; tad1(1)=T1

	mov rdx, rax		; dl=D1,A1
	shr rdx, 6		; 
	and rdx, 0x3F		; dl=A1
	mov dword [rdi+4], edx	; tad1(2)=A1

 	mov rdx, rax
 	shr rdx, 12
 	and rdx, 0xF		; dl=D1
	mov dword [rdi+8], edx	; tad1(3)=D1

; 	mov rdx, rax
; 	shr rdx, 30
; 	and rdx, 0x3
;	mov dword [rdi+12], edx	; tad1(4)=01
;				;
	shr rax, 32		; 

	mov rdx, rax		; dl=T1
	and rdx, 0x3F		; lower 6 bits
	mov rdi, [rbp-arg4]	; rdi= ptr tad2
	mov dword [rdi], edx	; tad1(2)=A2
	
	mov rdx, rax		; dl=D1,A1
	shr rdx, 6		; 
	and rdx, 0x3F		; dl=A1
	mov dword [rdi+4], edx	; tad1(2)=A2

	mov rdx, rax
	shr rdx, 12		;
	and rdx, 0xF		; dl=D1
	mov dword [rdi+8], edx	; tad1(3)=D2

; 	mov rdx, rax
; 	shr rdx, 30
; 	and rdx, 0x3
;	mov dword [rdi+12], edx	; tad1(4)=00
;	;; 
.exit:	
	;;
	pop rbp			; 
	ret
;OBS;;;; 
;OBS;;;; subroutine decv(pevent,nevent,plmbuf,nlmbuf,&
;OBS;;;; 			pnevent_read,pnlmbuf_wrote)
;OBS;;;; integer*8,intent(in)::pevent
;OBS;;;; integer*8,intent(in)::nevent
;OBS;;;; integer*8,intent(in)::plmbuf ! integer*4 lmbuf(6)
;OBS;;;; integer*8,intent(in)::nlmbuf
;OBS;;;; integer*8,intent(in)::pnevent_read
;OBS;;;; integer*8,intent(in)::pnlmbuf_wrote
;OBS;;;;
;OBS;%assign lmsize 24
;OBS;decv_:
;OBS;	push rbp
;OBS;	mov rbp, rsp
;OBS;	;;
;OBS;	mov [rbp-arg1], rdi 	; 1st event
;OBS;	mov [rbp-arg2], rsi	; 2nd nevent*2
;OBS;	mov [rbp-arg3], rdx	; 3rd plmbuf
;OBS;	mov [rbp-arg4], rcx	; 4th nlmbuf
;OBS;	mov [rbp-arg5], r8	; 5th pnevent_read
;OBS;	mov [rbp-arg6], r9	; 6th pnlmbuf_wrote
;OBS;	;; 
;OBS;	mov rsi, [rbp-arg1]	; rsi = ptr event
;OBS;	mov rdi, [rbp-arg3]	; rdi = ptr lmbuf
;OBS;	;;
;OBS;	mov rcx, [rbp-arg2]	; rcx = nevent
;OBS;	sub rsi, 4
;OBS;	inc rcx
;OBS;	;; 
;OBS;	mov rdx, [rbp-arg4]	; rdx = nlmbuf
;OBS;	or rdx, rdx
;OBS;	jz .done
;OBS;	sub rdi, lmsize
;OBS;	;; 
;OBS;	movq xmm7, [lmdmaskall]	; xmm7 = 0, 0, ffff, ffff
;OBS;	movq xmm6, [lmdmasklsb]	; xmm6 = 0, 0, 003f, 003f
;OBS;	movdqa xmm5, [a2d2a1d1conv] ; xmm5 = 1, 24, -1, 24
;OBS;	movdqa xmm0, [nac2]	    ; xmm0 = 0,0,C2,na
;OBS;	movdqa xmm8, [b0001]	; xmm8 = 0,0,0,-1
;OBS;	movdqa xmm9, [ntamax]	; xmm9 = 20-1,64-1,20-1,64-1
;OBS;.next:
;OBS;.islo:
;OBS;	add rsi, 4
;OBS;	dec rcx
;OBS;	jz .done
;OBS;	bt dword [rsi], 31	; flag is 0*b
;OBS;	jc .islo
;OBS;	;; 
;OBS;	bt dword [rsi], 30	; lower flag is 01b
;OBS;	jnc .islo
;OBS;.isup:
;OBS;	add rsi, 4
;OBS;	dec rcx
;OBS;	jz .done
;OBS;	bt dword [rsi], 31	; flag is 0*b
;OBS;	jc .islo
;OBS;	bt dword [rsi], 30	; upper flag is 00b
;OBS;	jc .isup
;OBS;.dodec:
;OBS;	bt dword [rsi], 14	; d2 must be >= 100b
;OBS;	jnc .next
;OBS;	bt dword [rsi-4], 14	; d1 must be less than 100b
;OBS;	jc .next
;OBS;	;;
;OBS;	movq xmm1, [rsi-4]
;OBS;	xor eax, eax		;
;OBS;	bt dword [rsi], 28	; prompt/delay
;OBS;	movq xmm2, xmm1
;OBS;	adc eax, eax
;OBS;	movq xmm3, xmm1
;OBS;	;; 
;OBS; 	pand xmm1, xmm7		; xmm1 = 0, 0, xxxx, xxxx	
;OBS;	psrld xmm2, 6		; xmm2 = *, *, *a2, *a1
;OBS;	pand xmm3, xmm6		; xmm3 = 0, 0, t2, t1
;OBS;	;; 
;OBS;	psrld xmm1, 12		; xmm1 = *, *, d2, d1
;OBS;	pand xmm2, xmm6		; xmm2 = 0, 0, a2, a1
;OBS;;;; check t1,t2,a1,a2 for overflow
;OBS;movdqa xmm12, xmm2		; xmm12 = 0, 0, a2, a1
;OBS;punpckldq xmm12, xmm3		; xmm12 = t2, a2, t1, a1
;OBS;pcmpgtd xmm12, xmm9		; xmm12 = t2>63, a2>19, t1>63, a1>19
;OBS;pmovmskb r8, xmm12		; r8 = a2>19.or.a2>19
;OBS;or r8, r8			;
;OBS;jnz .next			;
;OBS;;;; 
;OBS;	punpckldq xmm1, xmm1	; xmm1 = d2, d2, d1, d1
;OBS;	pxor xmm2, xmm8		; xmm2 = *,*,a2,-a1-1
;OBS; 	pmuludq	xmm1, xmm5	; xmm1 = *, d2*24, *, d1*24
;OBS;	;;
;OBS;	pshufd xmm1, xmm1, 10001000b ; xmm1 = d2*24,d1*24,d2*24,d1*24	
;OBS;	;; 
;OBS;	paddd xmm1, xmm0	; xmm1 = d2*24,d1*24,d2*24-C2,d1*24+na
;OBS;	;; 
;OBS;	punpckldq xmm1, xmm2	; xmm1 = a2, d2*24-C2, [-a1-1, d1*24+na]
;OBS;	;; 
;OBS;	phaddd xmm1, xmm1	; xmm1 = =,=,[a2+d2*24-C2, -a1-1+d1*24+na]	
;OBS;	;; 
;OBS;	punpckldq xmm1, xmm3	; xmm1 = t2,a2+d2*24-C2,t1,-a1-1+d1*24+na
;OBS;	;; 
;OBS;	add rdi, lmsize
;OBS;	movdqu [rdi], xmm1
;OBS;	mov [rdi+16], eax
;OBS;	dec rdx
;OBS;	jz .done
;OBS;	or rcx, rcx
;OBS;	ja .next
;OBS;.done:	
;OBS;.exit:
;OBS;	mov rax, [rbp-arg4]
;OBS;	sub rax, rdx
;OBS;	mov rdi, [rbp-arg6]
;OBS;	mov [rdi], rax
;OBS;	;; 
;OBS;	mov rax, [rbp-arg2]
;OBS;	sub rax, rcx
;OBS;	mov rdi, [rbp-arg5]
;OBS;	mov [rdi], rax
;OBS;	;;
;OBS;	pop rbp			; 
;OBS;	ret
;OBS;;;; 
;;; subroutine decs(event,tad)
;;; integer*8,intent(in)::event
;;; integer*4,intent(out)::xyz(3)
;;; integer*4,intent(out)::etc(3)
;;;
decs_:	
	push rbp
	mov rbp, rsp
	;;
;	mov [rbp-arg1], rdi 	; 1st event
;	mov [rbp-arg2], rsi	; 2nd xyz
;	mov [rbp-arg3], rdx	; 3rd etc
;	;;
	mov rax, rdi		; rax=ptr event
	mov rax, [rax]
	;; 
	mov rdi, rdx		; rdi = ptr etc
;	mov rsi, rsi		; rsi = ptr xyz
;	;; 
	mov rdx, rax
	and rdx, 0x3FF		; mask 10 bits
	mov dword [rdi], edx	; etc(1) = DOI
	;;
	shr rax, 10
	mov rdx, rax
	and rdx, 0x3FF		; mask 10 bits
	mov dword [rsi+8], edx	; xyz(3) = Z
	;;
	shr rax, 10
	mov rdx, rax
	and rdx, 0x3FF
	mov dword [rsi+4], edx	; xyz(2) = Y
	;; 
	shr rax, 10
	mov rdx, rax
	and rdx, 0x3
	mov dword [rdi+8], edx	; etc(3) = 0x1
	;;
	shr rax, 2
	mov rdx, rax
	and rdx, 0x3FF
	mov dword [rsi], edx	; xyz(1 )= X
	;;	
	shr rax, 10		;
	mov rdx, rax		;
	and rdx, 0xF		;
	mov dword [rdi+4], edx	; etc(2) = PMTID
	;; 
	shr rax, 18		;
	mov rdx, rax		;
	and rdx, 0x3		;
	mov dword [rdi+12], edx	; etc(4) = 0x0
;;
	pop rbp
	ret	
	
;;; 
;;; subroutine decvs(pevent,nevent,plmbuf,nlmbuf,&
;;; 			pnevent_read,pnlmbuf_wrote)
;;; integer*8,intent(in)::pevent
;;; integer*8,intent(in)::nevent
;;; integer*8,intent(in)::plmbuf ! integer*4 lmbuf(6)
;;; integer*8,intent(in)::nlmbuf
;;; integer*8,intent(in)::pnevent_read
;;; integer*8,intent(in)::pnlmbuf_wrote
;;;
%assign lmsize 16
decvq_:
	push rbp
	mov rbp, rsp
	;;
	mov [rbp-arg1], rdi 	; 1st event
	mov [rbp-arg2], rsi	; 2nd nevent*2
	mov [rbp-arg3], rdx	; 3rd plmbuf
	mov [rbp-arg4], rcx	; 4th nlmbuf
	mov [rbp-arg5], r8	; 5th pnevent_read
	mov [rbp-arg6], r9	; 6th pnlmbuf_wrote
	;; 
	mov rsi, [rbp-arg1]	; rsi = ptr event
	mov rdi, [rbp-arg3]	; rdi = ptr lmbuf
	;;
	mov rcx, [rbp-arg2]	; rcx = nevent
	sub rsi, 4
	inc rcx
	;; 
	mov rdx, [rbp-arg4]	; rdx = nlmbuf
	or rdx, rdx
	jz .done
	sub rdi, lmsize
	;; 
	movq xmm7, [lmdmaskall]	; xmm7 = 0, 0, ffff, ffff
	movq xmm6, [lmdmasklsb]	; xmm6 = 0, 0, 003f, 003f
	movdqa xmm5, [a2d2a1d1conv] ; xmm5 = 1, 24, -1, 24
	movdqa xmm0, [nac2]	    ; xmm0 = 0,0,C2,na
	movdqa xmm8, [b0001]	; xmm8 = 0,0,0,-1
	movdqa xmm9, [nt92amax]	; xmm9 = 20-1,(64-1)*92,20-1,(64-1)*92
	movdqa xmm10, [qnx]	; xmm10 = 0, 92, 0, 92
.next:
.islo:
	add rsi, 4
	dec rcx
	jz .done
	bt dword [rsi], 31	; flag is 0*b
	jc .islo
	;; 
	bt dword [rsi], 30	; lower flag is 01b
	jnc .islo
.isup:
	add rsi, 4
	dec rcx
	jz .done
	bt dword [rsi], 31	; flag is 0*b
	jc .islo
	bt dword [rsi], 30	; upper flag is 00b
	jc .isup
.dodec:
	bt dword [rsi], 14	; d2 must be >= 100b
	jnc .next
	bt dword [rsi-4], 14	; d1 must be less than 100b
	jc .next
	;;
	movq xmm1, [rsi-4]
	xor eax, eax		;
	bt dword [rsi], 28	; prompt/delay
	movq xmm2, xmm1
	adc eax, eax
	movq xmm3, xmm1
	;; 
 	pand xmm1, xmm7		; xmm1 = 0, 0, xxxx, xxxx	
	psrld xmm2, 6		; xmm2 = *, *, *a2, *a1
	pand xmm3, xmm6		; xmm3 = 0, 0, t2, t1
	;; 
	psrld xmm1, 12		; xmm1 = *, *, d2, d1
	pand xmm2, xmm6		; xmm2 = 0, 0, a2, a1
	punpckldq xmm3, xmm3	; xmm3 = t2, t2, t1, t1
	;; 
	pmuludq	xmm3, xmm10	; xmm3 = 0, t2*92, 0, t1*92
	;; 
	pshufd xmm3, xmm3, 10001000b	; xmm3 = t2*92, t1*92, t2*92, t1*92
	;; 
;;; check t1,t2,a1,a2 for overflow
movdqa xmm12, xmm2		; xmm12 = 0, 0, a2, a1
punpckldq xmm12, xmm3		; xmm12 = t2*92, a2, t1*92, a1
pcmpgtd xmm12, xmm9		; xmm12 = t2*92>63*92, a2>19, t1*92>63*92, a1>19
pmovmskb r8, xmm12		; r8 = a2>19.or.a2>19
or r8, r8			;
jnz .next			;
;;; 
	punpckldq xmm1, xmm1	; xmm1 = d2, d2, d1, d1
	pxor xmm2, xmm8		; xmm2 = *,*,a2,-a1-1
 	pmuludq	xmm1, xmm5	; xmm1 = *, d2*24, *, d1*24
	;;
	pshufd xmm1, xmm1, 10001000b ; xmm1 = d2*24,d1*24,d2*24,d1*24	
	;; 
	paddd xmm1, xmm0	; xmm1 = d2*24,d1*24,d2*24-C2,d1*24+na
	;; 
	punpckldq xmm1, xmm2	; xmm1 = a2, d2*24-C2, [-a1-1, d1*24+na]
	;; 
	phaddd xmm1, xmm1	; xmm1 = =,=,[a2+d2*24-C2, -a1-1+d1*24+na]	
	;; 
	paddd xmm1, xmm3	; xmm1 = =,=, [t2*92+a2+d2*24-C2, t1*92-a1-1+d1*24+na]
	;; 
	add rdi, lmsize		;
	movdqu [rdi], xmm1
	mov [rdi+8], eax
	dec rdx
	jz .done
	or rcx, rcx
	ja .next
.done:	
.exit:
	mov rax, [rbp-arg4]
	sub rax, rdx
	mov rdi, [rbp-arg6]
	mov [rdi], rax
	;; 
	mov rax, [rbp-arg2]
	sub rax, rcx
	mov rdi, [rbp-arg5]
	mov [rdi], rax
	;;
	pop rbp			; 
	ret
